AMÉLIORER LE PRODUIT IA DE VOTRE START-UP¶

logoAvisRestau

SYNTHESE GRAPHIQUE DES RESULTATS¶

L'objectif ici est de synthétiser les principaux résultats de l'analyse :

  • des commentaires négatifs pour détecter les sujets d'insatisfaction
  • des photos pour détecter leur catégorie

(Pour plus de détail et pour parcourir les différentes étapes ayant permis d'atteindre ces résultats, se référer au notebook principal)

In [1]:
# imports
# custom functions
import myFunctions as mf
%load_ext autoreload

%autoreload 2

# LDA
from gensim.models.ldamodel import LdaModel

# pyLDAvis
import pyLDAvis.gensim_models as gensimvis
import pyLDAvis

# file and directory management
import os
# to make saves
from joblib import dump, load  

# data viz
from matplotlib import pyplot as plt
%matplotlib inline
import seaborn as sns
# image annotations
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
from matplotlib.colors import ListedColormap, to_rgb

PARTIE I - ANALYSER LES COMMENTAIRES NÉGATIFS POUR DÉTECTER LES DIFFÉRENTS SUJETS D’INSATISFACTION¶

NLP - Méthode¶

L'objectif final est de détecter les sujets de mécontentement dans les avis qui seront postés sur Avis Restau. Le but ici n'est pas de réaliser ce projet entièrement mais de tester sa faisabilité. Pour cela nous avons la chance de disposer d'un jeu de données existant disponible sur la plateforme Yelp.

Nous réaliserons donc notre études préliminaire sur ce dataset :

  • Nous réaliserons les étapes préalables à l'entraînement d'une algorithme de détection de sujets :
    • sélectionner quelques milliers de commentaires négatifs
    • pré-traiter ces données :
      • mettre en minuscule,
      • tokeniser,
      • normaliser les mots via une lemmatisation,
      • etc.
    • création du dictionnaire et représentation de nos reviews en vecteurs bag-of-words
    • adapter la pondération des mots grâce à un TF-IDF
  • Nous testerons alors la faisabilité sur ce petit échantillons :
    • utiliser une technique de réduction de dimension de type topic-modeling pour extraire nos sujets d'insatisfaction sous-jacents de notre corpus. Nous utiliserons ici le Latent Dirichlet Allocation (LDA)
    • évaluer notre réduction afin de choisir le bon hyperparamètre num_topics
  • Enfin nous tâcherons de visualiser nos topics afin d'en détecter les mots-clés. Pour cela nous utiliserons 2 librairies :
    • wordcloud
    • pyLDAvis

NLP - Nos commentaires et leur nettoyage¶

Étapes du preprocessing :

  • charger un échantillon de reviews
  • mettre en minuscules
  • supprimer les url
  • supprimer les séquences d'échappement
  • corriger les mots avec des caractères répétés
  • cleaning général :
    • supprimer les ponctuations
    • supprimer les stopwords
    • supprimer les stopwords spécifiques métier
    • supprimer les nombres et les nombres écrits en lettres
    • filtrer sur les POS (en ne gardant que les adjectifs et noms)
    • normaliser les mots (ici : lemmatisation)
In [2]:
# load existing .joblib
rev = load("mySaves/rev/rev.joblib")
rev
Out[2]:
text lower withoutURL withoutEscSeq withoutDupl textClean tokensClean
1947 I came here for lunch and was very disappointe... i came here for lunch and was very disappointe... i came here for lunch and was very disappointe... i came here for lunch and was very disappointe... i came here for lunch and was very disappointe... disappointed bland expensive quality food luke... [disappointed, bland, expensive, quality, food...
5136 One star for really nice service + no wait (ca... one star for really nice service + no wait (ca... one star for really nice service + no wait (ca... one star for really nice service + no wait (ca... one star for really nice service + no wait (ca... star nice service wait hour bad meal grit mass... [star, nice, service, wait, hour, bad, meal, g...
5803 Fried rice looks like brown rice about 2 1/4 i... fried rice looks like brown rice about 2 1/4 i... fried rice looks like brown rice about 2 1/4 i... fried rice looks like brown rice about 2 1/4 i... fried rice looks like brown rice about 2 1/4 i... rice brown rice chunk egg vegtible water gun s... [rice, brown, rice, chunk, egg, vegtible, wate...
3459 I agree with some of the other commenters, the... i agree with some of the other commenters, the... i agree with some of the other commenters, the... i agree with some of the other commenters, the... i agree with some of the other commenters, the... commenter okay worth hype food good appetizer ... [commenter, okay, worth, hype, food, good, app...
7301 I used the mobile app, the bill was for $31 a... i used the mobile app, the bill was for $31 a... i used the mobile app, the bill was for $31 a... i used the mobile app, the bill was for $31 a... i used the mobile app, the bill was for $31 a... mobile app bill friend store order card time i... [mobile, app, bill, friend, store, order, card...
... ... ... ... ... ... ... ...
196744 Passing through Reno we stopped to get a bean ... passing through reno we stopped to get a bean ... passing through reno we stopped to get a bean ... passing through reno we stopped to get a bean ... passing through reno we stopped to get a bean ... reno bean burrito good rating yelp long time d... [reno, bean, burrito, good, rating, yelp, long...
199082 For over an hour we were told we were next. Wa... for over an hour we were told we were next. wa... for over an hour we were told we were next. wa... for over an hour we were told we were next. wa... for over an hour we were told we were next. wa... hour table staff food chance bloody mary bar a... [hour, table, staff, food, chance, bloody, mar...
197735 If you're on a clock, this is not the place fo... if you're on a clock, this is not the place fo... if you're on a clock, this is not the place fo... if you're on a clock, this is not the place fo... if you're on a clock, this is not the place fo... clock food good minute order good benefit doub... [clock, food, good, minute, order, good, benef...
191503 Stopped in for dinner break as I work in the p... stopped in for dinner break as i work in the p... stopped in for dinner break as i work in the p... stopped in for dinner break as i work in the p... stopped in for dinner break as i work in the p... dinner break promenade turkey burger good reas... [dinner, break, promenade, turkey, burger, goo...
191338 Ducked in to meet a local politician and talk ... ducked in to meet a local politician and talk ... ducked in to meet a local politician and talk ... ducked in to meet a local politician and talk ... ducked in to meet a local politician and talk ... local politician social digital marketing quai... [local, politician, social, digital, marketing...

10000 rows × 7 columns

NLP - Dictionnaire, BOW et TF-IDF¶

Nota : Par rapport à l'exemple ci-dessus, nous avons intégré plus de commentaires : 60000.

Étapes de traitement :

  • création dictionnaire
  • filtre sur la fréquence pour les mots rare et et pour les mots fréquents
  • conversion des documents en bag-of-words
  • pondération des documents par TF-IDF
In [3]:
# load existing .joblib
tfidf_vector = load("mySaves/nlpDictAndVector/tfidf_vector.joblib")
dictionary = load("mySaves/nlpDictAndVector/dictionary.joblib")

Exemple de document après le traitement :

In [4]:
display(tfidf_vector[16])
[(29, 0.09775788015223455),
 (115, 0.31639656093164764),
 (129, 0.22861969373276309),
 (233, 0.4524697946579984),
 (234, 0.4096645361564042),
 (235, 0.6038715712381316),
 (236, 0.31757648988015796)]

NLP - Latent Dirichlet Allocation et visualisations¶

Choix du nombre de topics basé sur le score de cohérence :

In [5]:
if "coherencesPlot.joblib" in os.listdir("mySaves/coherencesPlot") :
    # load existing .joblib
    load("mySaves/coherencesPlot/coherencesPlot.joblib")
No description has been provided for this image

Il n'y a pas vraiment de pic ... Nous observons néanmoins une chute de cohérence après 5 topics. Nous allons regarder ce que cela donne pour 3, 4 et 5 topics :

NLP - LDA - 3 topics¶

In [6]:
# create the LDA model 
model = LdaModel(
    corpus=tfidf_vector,
    num_topics=3,
    id2word=dictionary,
    random_state=16
)

Vue wordcloud et score de cohérence :

In [7]:
# use custom function wordCloudAndCoherence to display 1 wordcloud for each topic and compute coherence_score
mf.wordCloudAndCoherence(model=model, corpus=tfidf_vector)
No description has been provided for this image

Les limites d'une telle visualisation :

  • ne nous permet pas vraiment de comprendre le degré de différence entre les topics
  • apporte du biais aléatoire dans l'interprétation de l'importance des mots (orientation, position, couleur)
  • ne nous permet pas de visualiser l'importance relative des topics

Voyons ce que cela donne avec PyLDAvis :

pyLDAvis est une librairie spécialisée permettant de :

  • avoir une vue d'ensemble d'un modèle de topic modeling
  • explorer en détail chaque topic
  • explorer en détail chaque mot par rapport aux topics

Il est composé de plusieurs parties :

  • Intertopic Distance Map :
    • représentation 2D des topics dans l'espace des probabilités de mots dans les topics (matrice topics/mots issue du modèle de LDA). Cette réduction de dimension 2D est issue d'un MDS (multidimensional scaling)
    • la représentation de chaque topic dans cet espace réduit permet ainsi d'apprécier les distances qui les séparent les uns des autres dans l'espace plus large, et donc s'ils sont bien différents
    • la taille de chaque topic est elle liée à l'espace des probabilités des topics dans les documents (matrice documents/topics issue du modèle LDA). La somme des probabilités sur tous les documents de chaque topic permet de définir sa taille. Elle représente donc la prédominance du topic dans le corpus
  • liste des mots les plus importants :
    • sans spécifier un topic : Top-30 Most Salient Terms :
      • mots classés selon la saliency : liée à la fréquence globale de chaque mot dans le corpus.
      • barres bleus : fréquences à l'échelle du corpus
    • en sélectionnant un topic : Top-30 Most Relevant Terms for Topic n :
      • mots classés selon la relevance : liée à la probabilité de chaque mot dans un topic particulier. Ce classement évolue en fonction du paramètre λ :
        • λ tend vers 1 : la relevance met plus en avant les mots les plus présents au sein du topic
        • λ tend vers 0 : la relevance normalise cette probabilité du mot pour ce topic avec la probabilité du mot au global dans le corpus. On voit alors apparaître non pas les mots forcément les plus présents, mais les mots les plus distinctifs du topic analysé
      • barres rouges : fréquences estimées au sein du topic
    • il est aussi possible de sélectionner un mot en particulier : les tailles des topics de l'Intertopic Distance Map représentent alors seulement la répartion de ce mot choisi aux sein des topics.
In [8]:
# use the "prepare" function 
vis_data  = gensimvis.prepare(
    topic_model=model,
    corpus=tfidf_vector,
    dictionary=dictionary
)
# display
pyLDAvis.display(vis_data)
Out[8]:

Les 3 sujets de mécontentement :

  • le comportement du personnel et le temps d'attente, avec des mots comme table, server, minute, hour, rude, manager, experience, incorrect, customer, hostess, staff, etc.
  • le rapport qualité / prix, avec des mots comme flavor, bland, dry, taste, price, portion, small, etc.
  • la livraison, avec des mots comme delivery, order, hour, service, slow, min, minute, driver, phone, refund, etc.

NLP - LDA - 4 topics¶

In [9]:
# create the LDA model 
model = LdaModel(
    corpus=tfidf_vector,
    num_topics=4,
    id2word=dictionary,
    random_state=16
)

Vue wordcloud et score de cohérence :

In [10]:
# use custom function wordCloudAndCoherence to display 1 wordcloud for each topic and compute coherence_score
mf.wordCloudAndCoherence(model=model, corpus=tfidf_vector)
No description has been provided for this image

Vue PyLDAvis :

In [11]:
# use the "prepare" function 
vis_data  = gensimvis.prepare(
    topic_model=model,
    corpus=tfidf_vector,
    dictionary=dictionary
)
# display
pyLDAvis.display(vis_data)
Out[11]:

les 4 sujets se distinguent un peu plus :

  • le comportement du personnel et le temps d'attente, avec des mots comme minute, reservation, order, manager, rude, hour, employee, server, waitress, hostess, service, time, busy, attitude, etc.
  • la qualité du plat et son prix, avec des mots comme flavor, dry, bland, salty, quality, taste, poisonning, soggy, price, portion, small, etc.
  • l'hygiène, avec des mots comme dirty, flour, filthy, clean, hair, glove, mask, fly, bathroom, cleanliness, cockroach, rat, restroom, toilet, disgusting, bug, etc.
  • la livraison, avec des mots comme driver, delivery, uber, masked, order, drive, time, hour, slow, cold,etc.

NLP - LDA - 5 topics¶

In [12]:
# create the LDA model 
model = LdaModel(
    corpus=tfidf_vector,
    num_topics=5,
    id2word=dictionary,
    random_state=16
)

Vue wordcloud et score de cohérence :

In [13]:
# use custom function wordCloudAndCoherence to display 1 wordcloud for each topic and compute coherence_score
mf.wordCloudAndCoherence(model=model, corpus=tfidf_vector)
No description has been provided for this image

Vue PyLDAvis :

In [14]:
# use the "prepare" function 
vis_data  = gensimvis.prepare(
    topic_model=model,
    corpus=tfidf_vector,
    dictionary=dictionary
)
# display
pyLDAvis.display(vis_data)
Out[14]:

Les 5 sujets de mécontentement :

  • l'ambiance avec des mots comme table, reservation, music, loud, party, birthday, noisy, dance, etc.
  • l'attitude du personnel et le temps d'attente, avec des mots comme table, delivery, understaffed, reservation, minute, order, manager, rude, hour, employee, waitress, service, time, busy, attitude, etc.
  • 2 sujets très proches sur la nourriture, avec des mots en commun comme flavor, soggy, dry, taste, etc. :
    • l'un un peu plus axé sur la qualité du plat et son prix, avec des mots comme portion, price, small, quality, taste, etc.
    • l'autre se concentrant plus exclusivement sur la nourriture
  • l'hygiène, avec des mots comme dirty, filthy, bathroom, glove, floor, mask, health, restroom, toilet, disgusting, rat, cleaning, roach, hair, etc.

NLP - Conclusion¶

Il est difficile de conclure sur le nombre idéal de topics :

  • se contenter de 3 met de côté l'hygiène
  • conserver 4 topics est intéressant car les sujets sont clairs, avec l'hygiène qui se rajoute,
  • enfin avec 5 topics nous avons réussi à obtenir un sujet différent avec l'ambiance, mais la livraison disparaît et le rapport qualité/prix se divise en 2 sous-thèmes pas très clairs...

Nous pouvons néanmoins conclure sur le faisabilité du projet :

  • le fait d'ajouter plus de commentaires et d'affiner la préparation des données a permis de trouver de vrais sujets de mécontentement,
  • il est donc tout à fait possible :
    • que l'utilisation de toute la base de données nous permette de faire disparaître les limitations que nous avons observé
    • qu'une recherche plus poussée des meilleures paramètres de notre pipeline (gridsearchCV, BayesSearchCV, etc.) permette d'améliorer le modèle:
      • filtrage,
      • liste de stopwords,
      • le nombre de topics,
      • les autres hyper-paramètres du modèle (alpha et eta notamment, qui conditionne le côté plus ou moins lisse des distributions de chaque document en topics et de chaque topic en mots)
  • cependant il faut noter que :
    • nous avons dû ajouter "à la main" beaucoup de stopwords spécifiques... A voir si ce procédé peut d'une quelconque manière être évité...
    • après quelques essais il s'avère que les thèmes détectés par le modèle sont instables (notamment en fonction de la liste des stopwords spécifiques)

Il serait intéressant, dans le cadre de la poursuite du projet, de tester d'autres modèles (LSA? BERTopic? autre ?).

PARTIE II.A - ANALYSER LES PHOTOS POUR DÉTERMINER LES CATÉGORIES DES PHOTOS - SIFT¶

CV-SIFT - Méthode¶

Nous avons la chance que les photos Yelp soient déjà labellisées : L'objectif final est d'entraîner un algorithme de classification supervisée sur celles-ci afin d'utiliser le modèle ultérieurement sur les photos qui seront publiées sur Avis Restau.

Le but ici n'est pas de réaliser ce projet entièrement. L'objectif préliminaire est d'analyser les photos pour vérifier la faisabilité :

  • Nous réaliserons donc toutes les étapes préalables à l'entraînement d'un algorithme de classification :

    • réaliser le pré-traitement sur N images
    • extraire les features (nous utiliserons le SIFT) pour obtenir les descripteurs de nos N images
    • création des bag-of-visual-words :
      • trouver les "visual words" grâce à un algorithme KMeans appliqué sur l'ensemble des descripteurs trouvés
      • construire l'histogramme de chaque image en fonction de ce dictionnaire de "visual-words"
      • contruire ainsi notre matrice des "bag-of-visual-words", de taille N images X taille dictionnaire
    • adapter la pondération des visual-words grâce à un TF-IDF

    ... mais au lieu de réaliser ce travail sur un très grand nombre de photos (avec un split préalable en train/test set, etc.), nous ne prendrons que quelques photos de chaque catégorie.

  • Nous testerons alors la faisabilité sur ce petit échantillon avec un clustering KMeans avec K = le nombre de labels pour vérifier que nos features peuvent bien regrouper nos labels :

    • réduction de dimension préalable via une ACP
    • appliquer le KMeans
    • effectuer une mesure de similarité ARI
    • analyser les catégories les mieux regroupées (via une matrice de confusion entre les catégories et les clusters prédits)

  • Nous tâcherons également de visualiser nos N images dans cet espace des features pour analyser si les catégories/labels fournies ressortent :

    • utilisation du même espace réduit par l'ACP
    • réduction de dimension par T-SNE, idéal pour représenter des données en grande dimension
    • visualisation :
      • des catégories
      • des clusters

CV-SIFT - Nos image et leur traitement¶

Étapes du preprocessing :

  • charger un échantillon d'images
  • mettre en nuance de gris
  • égalisation d'histogramme
  • filtre gaussien
  • extraire les features descripteurs SIFT

Nous pouvons regarder ce que cela donne visuellement :

In [15]:
# load existing .joblib
examplesPhotoDict = load("mySaves/examplesPhotoDict/examplesPhotoDict.joblib")

# create a figure
fig, axs = plt.subplots(2,5, figsize=(14,6))

# choose a category example
cat = "drink"

# plot the two images stored in the dict for this category, for each preprocessing step
for i,phase in enumerate(['raw', 'gray', 'equal', 'gaussian', 'keypoints']) :
    for j,img in enumerate(examplesPhotoDict[phase][cat]) :
        # plot
        # handle grayscale
        if len(img.shape) == 2 :
            axs[j,i].imshow(img, cmap='gray',vmin=0,vmax=255)
        else :
            axs[j,i].imshow(img)

        # set anchor
        axs[j,i].set_anchor("N")
        # remove axis
        axs[j,i].axis(False)
        # title on top axes 
        if j==0 :
            axs[j,i].set_title(phase)

# sup title
fig.suptitle("Photo cleaning steps")

plt.show()
No description has been provided for this image

CV-SIFT - Dictionnaire, Bag-of-Visual-Words, TF-IDF, PCA¶

Étapes de traitement :

  • Création d'un dictionnaire de visual words :
    • rassemblement de tous les descripteurs des images
    • utilisation d'un algorithme de clustering (MiniBatchKMeans) : chaque centroïde de cluster correspond à un visual word
  • Création matrice des Bag-of-Visual-Words :
    • pour chaque descripteur de chaque image, appliquer le modèle de clustering (dictionnaire) pour attibuer le visual word correspondant
    • pour chaque image, compter le nombre d'occurences de chaque visual word présent
    • intégrer ces histogrammes à une matrice (nombre d'images X nombre de visual words)
  • Appliquer la pondération TF-IDF
  • Appliquer une analyse en composantes principales PCA pour :
    • réduire le nombre de dimension (curse of dimensionality)
    • faciliter le travail du futur modèle (temps et mémoire)

Nous avons alors un dataframe comportant une ligne par image et une colonne par composante principale :

In [16]:
# load existing .joblib
siftFeatures = load("mySaves/siftFeatures/siftFeatures.joblib")
siftFeatures
Out[16]:
C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 ... C599 C600 C601 C602 C603 C604 C605 C606 C607 C608
0 -0.079165 -3.800291 14.066756 0.984657 5.144575 8.648161 -7.180452 -2.898898 1.124841 -4.255499 ... 0.102363 0.020066 -0.124666 -0.117224 0.042325 -0.562461 0.590468 -0.214824 0.246502 -0.510977
1 4.668302 -1.241076 -3.295023 2.710035 -2.393686 1.030828 7.408102 2.990802 -2.122968 -2.902438 ... -0.028090 -0.369633 -0.578845 -0.095885 0.317662 0.184974 -0.006934 -0.003246 -0.325203 -0.115126
2 -0.501951 -5.224448 -5.325085 3.149939 1.008314 -1.202440 5.776378 -2.664012 -2.610973 -1.214457 ... -0.278282 0.357192 0.327380 0.206463 -0.174073 -0.166300 0.212760 -0.036203 -0.078368 -0.545426
3 -7.326880 -9.606032 -3.030050 -0.454922 -1.654513 -1.160068 -0.884439 2.996916 -3.937234 0.063916 ... 0.034189 0.162919 -0.282017 0.042890 -0.397165 -0.154988 -0.453393 0.653721 -0.202591 0.492679
4 1.945519 -2.702972 0.182178 1.762309 -2.828546 6.268726 -0.672833 -0.646871 1.104524 -6.210130 ... 0.132200 -0.208414 0.130558 -0.156949 -0.338585 0.188776 0.126383 0.226559 0.037979 0.339935
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
745 -0.748908 3.689911 -3.130025 -4.271580 -1.739386 -4.707257 -3.908305 -0.412259 4.291135 -0.658773 ... -0.072263 -0.949471 0.220239 -0.276538 0.534357 -0.243438 0.089219 0.116614 -0.029192 0.164529
746 -0.979159 -2.489993 -2.394485 -3.009860 -3.376783 5.438454 -5.294117 0.150032 4.145790 -2.446929 ... 0.449788 0.160142 -0.031747 -0.358067 -0.512304 -0.431860 0.542046 -0.429891 0.129443 -0.421667
747 7.316390 -7.549401 -3.281177 -5.320557 7.607325 -0.349459 -6.333130 -2.863415 -1.719797 2.862377 ... 0.039158 0.149544 -0.735282 0.220999 0.444086 -0.087249 -0.062941 0.317693 0.220423 0.127270
748 -4.471304 -6.847694 -9.406762 -4.260997 2.071330 2.058631 2.733293 -0.932200 -0.403964 2.632530 ... -0.025071 0.134067 0.306671 0.381223 0.082204 -0.573076 -0.320897 -0.533770 0.029683 0.137277
749 -10.251017 -3.028337 4.381681 -1.659601 3.600789 -2.654735 -1.667317 2.144917 -1.502747 -0.583928 ... 0.258883 0.294049 0.140972 -0.600434 0.387110 -0.327360 -0.257897 -0.747806 0.086976 0.010088

750 rows × 609 columns

CV-SIFT - Clustering - Kmeans¶

Nous allons maintenant vérifier s'il serait faisable de labelliser automatiquement nos photos. Pour cela nous n'allons pas utiliser d'algorithme de classification supervisée (pour rappel nous avons fait le choix d'utiliser peu de données), mais un modèle de clustering. Cela nous permettra d' analyser, à ce stade préliminaire, si les features que nous venons de créer permettent de regrouper nos catégories dans des clusters.

Étapes de l'étude de faisabilité :

  • algorithme de clustering avec, pour rappel, K = le nombre catégories de photo
  • calcul de l'ARI entre les labels des clusters et les catégories
  • projection de nos données en 2D grâce à un TSNE
  • représentation des clusters et des vraies catégories sur cet espace

L'ARI pour cette méthode SIFT n'est pas très bon : < 0.15 ... Notre clustering n'est pas une réussite. On le remarque assez bien sur la projection T-SNE :

In [17]:
# use existing .joblib
load("mySaves/figures/figSIFTscatter.joblib")
Out[17]:
No description has been provided for this image

La seule classe intéressante en termes de résultat est "menu". On peut vérifier également cela en remplaçant quelques points par leurs images respectives :

In [18]:
# use existing .joblib
load("mySaves/figures/figSIFTphotos.joblib")
Out[18]:
No description has been provided for this image

Le SIFT ne nous permet pas vraiment de conclure positivement quant à l'opportunité de développer un modèle de classification supervisée... Essayons maintenant avec du Transfer Learning :

PARTIE II.B - ANALYSER LES PHOTOS POUR DÉTERMINER LES CATÉGORIES DES PHOTOS - TRANSFER LEARNING¶

CV-TL - Utiliser un VGG16 pré-entraîné comme un extracteur de features autonome¶

Ici les étapes de traitement diffèrent un peu :

  • Charger nos photos et les préparer pour le VGG16 :
    • les charger à la taille 224 x 224
    • les convertir en array
    • les rassembler en un seul array
    • les convertir en BGR
    • centrer chaque canal de couleur
  • Utiliser un VGG16 déjà entraîné comme un extracteur de features :
    • retirer la dernière couche fully-connected (celle contenant la fonction d'activation Softmax nous donnant normalement nos scores par classe)
    • se servir de la sortie de la couche précédente comme features
  • Appliquer également une réduction de dimensions par PCA
In [19]:
# load existing .joblib
vgg16Features = load("mySaves/transferLearningFeatures/reducedVGG16featuresDf.joblib")
vgg16Features
Out[19]:
C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 ... C658 C659 C660 C661 C662 C663 C664 C665 C666 C667
0 -0.846850 -11.891654 -6.117408 -0.321572 -4.291137 -10.926862 6.937528 -4.013148 1.305520 -6.764181 ... 0.275987 0.232464 0.458611 0.543960 0.558130 0.222813 -0.290001 -0.539138 0.441324 -0.017959
1 5.037025 -13.103478 -21.579805 -3.339313 17.819710 -8.520625 8.204929 -10.765649 9.014797 3.520934 ... 0.055822 -0.086640 0.150894 -0.264949 -0.387565 -0.202633 0.066698 0.056778 0.600761 0.214788
2 9.072474 -11.708897 -6.724650 3.355097 -4.021892 -4.834295 3.494538 -10.439341 1.280492 -3.690792 ... 0.361371 0.752302 1.039641 -0.582730 1.270271 -0.051765 -0.014603 -0.750147 -0.315628 -0.322555
3 7.830352 -15.519650 -2.015309 -5.825803 -3.770918 -4.440335 -0.899613 2.694433 -7.181771 2.514869 ... -1.738357 0.746954 -0.229128 0.235237 1.069740 1.198662 -1.320371 -0.212548 1.796935 -0.858946
4 9.490551 -11.651093 -16.992430 10.883677 5.122124 -1.120993 -1.717786 4.987165 -8.951221 3.050616 ... -0.412974 0.353927 -0.452747 0.155640 0.352392 -0.223588 0.204226 -0.338285 -0.314118 0.486172
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
745 -16.692192 -3.265703 8.305225 -0.597627 2.250128 -0.669426 2.502982 6.066919 13.828831 -2.058198 ... 1.354470 0.674851 -0.447909 -0.068569 0.513947 1.289411 0.007111 0.686466 0.755736 0.022067
746 -21.897047 3.863275 19.063433 17.120266 2.947626 0.455507 -7.644225 8.272452 -10.308472 6.402745 ... -1.173490 0.004134 -0.166072 0.161261 0.581118 -0.153856 0.496201 -0.710096 0.551586 0.497768
747 -22.948324 -3.751245 14.161858 5.887580 -6.787694 -16.807522 16.557436 13.814086 -10.116261 2.190607 ... -0.717053 -0.321911 0.160335 -0.334540 -1.048403 0.455534 0.471592 0.863454 -0.557402 -0.150942
748 -5.360372 -6.883369 3.313624 -0.890294 -5.239982 4.500829 19.392597 4.678927 -11.867502 25.445805 ... 0.773634 -0.563206 0.248252 0.153675 0.176950 0.101078 0.064125 -0.137391 -0.173470 0.014518
749 -20.396402 -1.092745 12.486311 6.833673 4.355201 -3.832258 -0.639914 3.972427 4.758598 14.303320 ... 0.424066 -0.625958 0.875880 0.002121 1.905194 0.037119 0.323795 0.278523 2.208139 -0.139011

750 rows × 668 columns

CV-TL - Clustering - Kmeans¶

L'ARI pour cette méthode Transfer Learning est bien meilleur : > 0.70 ... On le remarque assez bien sur la projection T-SNE :

In [20]:
# use existing .joblib
load("mySaves/figures/figTLscatter.joblib")
Out[20]:
No description has been provided for this image

La correspondance est bonne. On peut vérifier également cela en remplaçant quelques points par leurs images respectives :

In [21]:
# use existing .joblib
load("mySaves/figures/figTLphotos.joblib")
Out[21]:
No description has been provided for this image

Le VGG16 en tant qu'extracteur de features donne de bien meilleurs résultats.

On peut conclure qu'il serait opportun de poursuivre le projet avec le développement d'un modèle de classification supervisée (avec bien plus de photos).